/*
 Автор: Швейкин Евгений Юрьевич
 Имя модуля: ad9826_ctrl


 Функциональное описание:     
    Модуль выполняет управление АЦП AD9826.
    
*/
//--------------------------------------------------------------------------------------------------

// *********************** НАЧАЛО МОДУЛЯ ***********************************************************
module ad9826_ctrl
#(
    parameter int unsigned clk_freq_p    =   32'd100_000_000,
    parameter int unsigned sclk_freq_p   =   32'd1_000_000
)
(
    input  logic            reset_n,
    input  logic            clk,
    
    input  logic            set,
    input  logic [2:0]      addr,
    input  logic [8:0]      register,
    
    output logic            sdata,
    output logic            sclk,
    output logic            sload,

    input  logic            adcclk,
    input  logic [7:0]      data_i,

    output logic [15:0]     data_o,
    output logic            valid
    
);

// ********************** МАКРОСЫ ******************************************************************
    // Описывает процесс модуля выделения фронтов сигнала. 
    // Так же описывает создание новых сигналов с именем <имя сигнала> + <_rise> (<_fall>, <_edge>)
    `define front(clk, name)                    \
    logic name``_0;                             \
    logic name``_1;                             \
    logic name``_rise;                          \
    logic name``_fall;                          \
    logic name``_edge;                          \
    always_ff @(posedge clk)                    \
    begin                                       \
        name``_0 <= name;                       \
        name``_1 <= name``_0;                   \
        name``_rise <= name``_0 & (~name``_1);  \
        name``_fall <= name``_1 & (~name``_0);  \
        name``_edge <= name``_0 ^ name``_1;     \
    end
//  ********************* КОНСТАНТЫ ****************************************************************
    // максимальное значение счетчика должно быть равно половине периода формируемого сигнала
    localparam int unsigned sclk_cnt_max_lp  = clk_freq_p / sclk_freq_p / 2;
    
//  ********************* ТИПЫ ДАННЫХ **************************************************************
    
//  ********************* ПЕРЕМЕННЫЕ ***************************************************************
    logic [15:0]    msg;            // Передаваемое сообщение. Сдвиговый регистр. 
    logic [15:0]    msg_latch;      // Защелкнутое сообщение по уровню
    
    logic [4:0]     bit_cnt;        // Счетчик бит передаваемого сообщения
    
    logic [31:0]    sclk_cnt;       // Счетчик для формирования тактовой интерфейса управления
	
    logic [7:0]     data_latch;     // Защелкнутые данные
// ********************* INITIAL *******************************************************************

//  ********************* ФУНКЦИИ ******************************************************************

//  ********************* ASSIGN *******************************************************************


// ********************* ПРОЦЕССЫ ******************************************************************
    `front (clk, sclk)
    `front (clk, adcclk)
    `front (clk, set)
    
    // Тут мы из старшей и младшей части делаем одно слово
    always_ff @(posedge clk)       
    begin   
        // По переднему фронту adcclk хватаем старший байт
        if (adcclk_rise) begin
            data_latch  <= data_i;
            valid       <= 1'b0;
        end
        // По заднему фронту adcclk хватаем младший байт
        else if (adcclk_fall) begin
            // data_latch[7:0] <= data_i;
			data_o <= {data_latch, data_i};
            valid       <= 1'b1;
        end
        else;
    end
    
    // Формируем выходную частоту последовательного интенрфейса
    always_ff @(posedge clk)       
    begin  
        sclk_cnt    <= sclk_cnt + 32'd1;
        if (sclk_cnt >= sclk_cnt_max_lp) begin
            sclk_cnt    <= 32'd0;
            sclk        <= ~sclk;
        end
        else;
    end
    
    // Защелка параметров сообщения
    always_ff @(posedge clk)       
    begin
        if (set) begin
            msg_latch[15]     <= 1'b0;        // Операция записи
			// Временно, пока не иправят программу
		//	if (addr == 1)
//				msg_latch[14:12]  <= 2;        // Адрес регистра	
//			else if (addr == 2)
//				msg_latch[14:12]  <= 5;        // Адрес регистра	
//			else;
            msg_latch[14:12]  <= addr;        // Адрес регистра
            msg_latch[11:9]   <= 3'd0;        // Три идла
            msg_latch[8:0]    <= register;    // Записываемые данные
        end
        else;
    end
    
    always_ff @(posedge clk)
    begin
        // Получив запрос на отправку сбросим счетчик битов
        // И перенесем защелкнутые параметры в регистр передаваемого сообщения
        if (set_rise) begin
            bit_cnt <= 5'd16;
            msg     <= msg_latch;
        end
        else;

		// Работаем только по заднему фронту тактовой
		if (sclk_fall) begin
			// Если преданы не все биты сообщения
			if (bit_cnt > 0) begin	
				sload   <= 1'b0;
				bit_cnt <= bit_cnt - 5'd1;
				sdata   <= msg[bit_cnt - 1];
			end
			else begin
				// Только когда счетчик битов обнулен, поднимаем сигнал
				sload   <= 1'b1;
			end
		end
    end
        
// ********************* ПОДКЛЮЧАЕМЫЕ МОДУЛИ *******************************************************
   
endmodule 